package com.websocket.converter;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.type.TypeFactory;
import com.websocket.exception.MessageDeserializeException;
import com.websocket.exception.MessageSerializeException;
import org.springframework.util.Assert;

import java.lang.reflect.Parameter;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

public class MessageConverter {
    private final ObjectMapper objectMapper;

    public MessageConverter(ObjectMapper objectMapper) {
        Assert.notNull(objectMapper, "message converter can not be null");
        this.objectMapper = objectMapper;
    }

    public String stringify(Object obj) {
        try {
            return objectMapper.writeValueAsString(obj);
        } catch (JsonProcessingException e) {
            throw new MessageSerializeException(e);
        }
    }

    public Object reParse(Object msg, Parameter parameter) {
        return parse(stringify(msg), parameter);
    }

    public Object parse(String msg, Parameter parameter) {
        JavaType javaType = getJavaType(parameter);
        return parse(msg, javaType);
    }

    public <T> T parse(String msg, Class<T> cls) {
        try {
            return objectMapper.readValue(msg, cls);
        } catch (JsonProcessingException e) {
            throw new MessageDeserializeException("error deserialization websocket message: " + msg + "\n" + e.getMessage());
        }
    }

    public Object parse(String msg, JavaType javaType) {
        try {
            return objectMapper.readValue(msg, javaType);
        } catch (JsonProcessingException e) {
            throw new MessageDeserializeException("error deserialization websocket message: " + msg + "\n" + e.getMessage());
        }
    }

    /**
     * 获取方法参数的类型，可以是各种复杂类型（如泛型、对象、对象中属性存在泛型等）
     */
    public JavaType getJavaType(Parameter parameter) {
        TypeFactory typeFactory = TypeFactory.defaultInstance();
        return getJavaType(parameter.getParameterizedType(), typeFactory);
    }

    private JavaType getJavaType(Type type, TypeFactory typeFactory) {
        if (type instanceof ParameterizedType parameterizedType) {
            Class<?> rawClass = (Class<?>) parameterizedType.getRawType();
            Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();

            JavaType[] javaTypeArguments = new JavaType[actualTypeArguments.length];
            for (int i = 0; i < actualTypeArguments.length; i++) {
                javaTypeArguments[i] = getJavaType(actualTypeArguments[i], typeFactory);
            }

            return typeFactory.constructParametricType(rawClass, javaTypeArguments);
        } else if (type instanceof Class<?>) {
            return typeFactory.constructType(type);
        }

        // 处理其他类型，例如TypeVariable、WildcardType等
        return null;
    }
}
